<!DOCTYPE html>
<html lang="cn">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Assign</title>

    <script src="https://unpkg.com/vue"></script>
    <link rel="stylesheet" href="https://unpkg.com/element-plus/dist/index.css" />
    <script src="https://unpkg.com/element-plus"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>

<body>
    <div id="app">
        <!-- 统计组件 -->
        <el-row>
            <el-col :span="5">
              <el-statistic title="请求总数" :value="info.requestTotal" @click="showText(info.requestMap)"/>
            </el-col>
            <el-col :span="5">
              <el-statistic title="待下发的任务" :value="info.taskMapTotal" @click="showText(info.taskMap)"/>
            </el-col>
            <el-col :span="5">
              <el-statistic title="运行中的任务" :value="info.runTaskQueueTotal" @click="showText(info.runTaskQueue)"/>
            </el-col>
            <el-col :span="5">
              <el-statistic title="异常的任务" :value="info.errTaskMapTotal" @click="showText(info.errTaskMap)"/>
            </el-col>
            <el-col :span="4">
              <el-statistic title="全部任务" :value="info.tasksTotal" @click="showText(taskList)"/>
            </el-col>
        </el-row>
        <el-row>
            <el-col :span="5">
              <el-statistic title="待分配" :value="tailor(info.requestMap)" @click="showText(info.requestMap)"></el-statistic>
            </el-col>
            <el-col :span="5">
              <el-statistic title="待下发" :value="tailor(info.taskMap)" @click="showText(info.taskMap)"></el-statistic>
            </el-col>
            <el-col :span="5">
              <el-statistic title="运行中" :value="tailor(info.runTaskQueue)" @click="showText(info.runTaskQueue)"></el-statistic>
            </el-col>
            <el-col :span="5">
              <el-statistic title="异常详情" :value="tailor(info.errTaskMap)" @click="showText(info.errTaskMap)"></el-statistic>
            </el-col>
            <el-col :span="4">
              <el-statistic title="过期时间" :value="tailor(new Date(info.expiredTime - 28800000).toLocaleTimeString())" @click="showText(info.expiredTime + 'ms')"></el-statistic>
            </el-col>
            <!-- <el-col :span="4">
              <el-statistic title="定时器id" :value="tailor(info.timeoutId || 'none')" @click="showText(info.timeoutId)"></el-statistic>
            </el-col> -->
        </el-row>
        <!-- 功能组件 -->
        <el-row class="margin">
            <el-col :span="12">
                <el-button type="success" size="small" @click="showAddd()">添加任务</el-button>
                <el-button type="primary" size="small" @click="list()">刷新列表</el-button>
                <el-button type="danger" size="small" @click="del()">删除选中</el-button>
                <el-button type="primary" size="small" @click="refresh()">重载服务器</el-button>
                <el-button type="success" size="small" @click="help()">使用帮助</el-button>
            </el-col>
            <el-col :span="12">
                <!-- 分页插件 -->
                <div class="demo-pagination-block">
                    <el-pagination

                        v-model:current-page="where.page"
                        v-model:page-size="where.limit"
                        :page-sizes="pageSizeList"
                        background
                        layout="total, sizes, prev, pager, next, jumper"
                        :total="where.total"
                        @size-change="handleSizeChange"
                        @current-change="handleCurrentChange"
                    >
                    </el-pagination>
                </div>
            </el-col>
        </el-row>
        <!-- 表单组件 -->
        <el-table
            :data="taskList"
            style="width: 100%"
            height="600"
            @selection-change="handleSelectionChange"
            >
            <!-- height="250" -->
            <el-table-column type="selection" width="55"></el-table-column>
            <el-table-column prop="id" label="ID" width="80"></el-table-column>
            <el-table-column prop="path" label="文件路径" width="200">
                <template #default="{row}">
                    <div @click="showText(row.path)">
                        {{ row.path }}
                    </div>
                </template>
            </el-table-column>

            <el-table-column prop="acquiredTime" label="上次获取时间" width="180">
                <template #default="{row}">
                    {{ formatDate(row.acquiredTime) }}
                </template>
            </el-table-column>
            <el-table-column prop="finishTime" label="上次完成时间" width="180">
                <template #default="{row}">
                    {{ formatDate(row.finishTime) }}
                </template>
            </el-table-column>
            <el-table-column prop="runStatus" label="运行状态" width="120"></el-table-column>
            <el-table-column prop="createTime" label="创建时间" width="180">
                <template #default="{row}">
                    {{ formatDate(row.createTime) }}
                </template>
            </el-table-column>
            <el-table-column prop="progress" label="当前进度" width="120"></el-table-column>
            <el-table-column prop="progressList" label="进度顺序" show-overflow-tooltip>
                <template #default="{row}">
                    <div @click="showText(row.progressList)">
                        {{ row.progressList }}
                    </div>
                </template>
            </el-table-column>
            <el-table-column prop="data" label="全程数据" show-overflow-tooltip>
                <template #default="{row}">
                    <div @click="showText(row.data)">
                        {{ row.data }}
                    </div>
                </template>
            </el-table-column>
            <el-table-column prop="request" label="请求信息" show-overflow-tooltip>
                <template #default="{row}">
                    <div @click="showText(row.request)">
                        {{ row.request }}
                    </div>
                </template>
            </el-table-column>
            <el-table-column prop="response" label="响应信息" show-overflow-tooltip>
                <template #default="{row}">
                    <div @click="showText(row.response)">
                        {{ row.response }}
                    </div>
                </template>
            </el-table-column>
            <el-table-column prop="historyResponse" label="历史响应信息" show-overflow-tooltip>
                <template #default="{row}">
                    <div @click="showText(row.historyResponse)">
                        {{ row.historyResponse }}
                    </div>
                </template>
            </el-table-column>
            <el-table-column fixed="right" label="选项" width="150">
                <template #default="scope">
                    <el-button type="primary" size="small" @click="showEdit(scope.row)">编辑</el-button>
                    <el-button type="danger" size="small" @click="del([scope.row.id])">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
        <!-- 弹出层 -->
        <el-drawer v-model="editInfo.show" :title="editInfo.addMode? '添加任务' : '编辑任务'" :with-header="false">
           
            <el-form :model="editInfo.task" label-width="120px" class="demo-ruleForm">
                <el-form-item label="ID" v-if="!editInfo.addMode">
                <el-input v-model="editInfo.task.id" placeholder="请输入ID"></el-input>
                </el-form-item>
                <el-form-item label="路径" v-if="!editInfo.addMode">
                <el-input v-model="editInfo.task.path" placeholder="请输入路径"></el-input>
                </el-form-item>
                <el-form-item label="上次获取时间" v-if="!editInfo.addMode">
                <el-date-picker v-model="editInfo.task.acquiredTime" type="datetime" placeholder="选择日期时间"></el-date-picker>
                </el-form-item>
                <el-form-item label="上次完成时间" v-if="!editInfo.addMode">
                <el-date-picker v-model="editInfo.task.finishTime" type="datetime" placeholder="选择日期时间"></el-date-picker>
                </el-form-item>
                <el-form-item label="运行状态" v-if="!editInfo.addMode">
                <el-input v-model="editInfo.task.runStatus" placeholder="请输入运行状态"></el-input>
                </el-form-item>
                <el-form-item label="创建时间" v-if="!editInfo.addMode">
                <el-date-picker v-model="editInfo.task.createTime" type="datetime" placeholder="选择日期时间"></el-date-picker>
                </el-form-item>
                <el-form-item label="当前进度" v-if="!editInfo.addMode">
                <el-input v-model="editInfo.task.progress" placeholder="请输入进度"></el-input>
                </el-form-item>
                <el-form-item label="配置的顺序">
                <el-input v-model="editInfo.task.progressList" placeholder="请输入配置的顺序"></el-input>
                </el-form-item>
                <el-form-item label="全程需要的字段">
                <el-input v-model="editInfo.task.data" placeholder="请输入全程需要的字段"></el-input>
                </el-form-item>
                <el-form-item label="请求信息">
                <el-input v-model="editInfo.task.request" placeholder="请输入请求信息"></el-input>
                </el-form-item>
                <el-form-item label="响应信息">
                <el-input v-model="editInfo.task.response" placeholder="请输入响应信息"></el-input>
                </el-form-item>
                <el-form-item label="历史响应信息" v-if="!editInfo.addMode">
                <el-input v-model="editInfo.task.historyResponse" placeholder="请输入历史响应信息"></el-input>
                </el-form-item>
                <el-form-item>
                <el-button type="primary" @click="submitForm">提交</el-button>
                <el-button @click="resetForm">重置</el-button>
                </el-form-item>
            </el-form>
        </el-drawer>
        
</body>
</html>

<script>

    function getData(){
        return {
            helpText: `
                使用说明：
                /task/add 添加任务到云端。
                /task/pull 脚本拉取任务。
                /task/heartbeat 脚本心跳，处理长时间任务时需要。
                /task/commit 执行完成，提交任务。
                当任务进度 progress 大于或等于 progressList 流程总数，则判定任务结束。
            `,
            selectIds: [],
            pageSizeList: [10, 20, 50, 100, 300, 500, 10000],
            where: {
                page: 1,
                limit: 10,
                total: 100,
            },
            taskList: [],
            editInfo: {
                show: false,
                addMode: false,
                task: {},
                orgTask: {}
            },
            info: {
                dn: Date.now(),
                requestMap: {},
                requestTotal: 0,
                taskMap: {},
                taskMapTotal: 0,
                runTaskQueue: [],
                runTaskQueueTotal: 0,
                errTaskMap: [],
                errTaskMapTotal: 0,
                timeoutId: "",
                tasksTotal: 0,
                expiredTime: 10*60*1000,
            }
        }
    }
    
    function getMethods(vueData) {
        let that;
        let methods = {
            tailor(obj) {
                let str = obj;
                if(typeof str !== "string") str = JSON.stringify(str);
                return str.substring(0, 30);
            },
            help(){
                that.showText(that.helpText);
            },
            showText(obj) {
                ElMessageBox.confirm(obj)
            },
            handleSelectionChange(val){
                that.selectIds = val;
            },
            formatDate(dateString){
                const date = new Date(dateString);
                const year = date.getFullYear();
                const month = String(date.getMonth() + 1).padStart(2, '0');
                const day = String(date.getDate()).padStart(2, '0');
                const hours = String(date.getHours()).padStart(2, '0');
                const minutes = String(date.getMinutes()).padStart(2, '0');
                const seconds = String(date.getSeconds()).padStart(2, '0');

                return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
            },
            handleSizeChange(page){
                that.handleCurrentChange(page);
            },
            handleCurrentChange(page){
                that.where.page = page;
                that.list();
            },
            list() {
                warpAxios(axios.post('/api/task/all', that.where)
                .then(function(response) {
                    let data = response.data.data;
                    // 处理数据
                    that.taskList.splice(0, that.taskList.length)
                    data.list.forEach(task=>that.taskList.push(task));

                    that.where.total = data.total;
                    // 这里需要用 Vue.set() 但是不知道Vue在哪里
                    for (const key in data.info) {
                        that.info[key] = data.info[key];
                    }
                    
                    // 在这里处理响应数据
                    ElMessage.success('获取成功')
                }))
            },
            setTaskForm(task){
                let keys = Object.keys({
                    progressList: [],
                    data: {},
                    request: {},
                    response: {}
                });
                keys.forEach(key=>{
                    if(typeof task[key] == "object"){
                        if(task[key]) {
                            task[key] = JSON.stringify(task[key]);
                        }
                    }
                })
                that.editInfo.orgTask = {...task};
                that.editInfo.task = task;
            },
            showAddd(task) {
                that.editInfo.show = true;
                that.editInfo.addMode = true;
                that.setTaskForm({
                    progressList: [],
                    data: {},
                    request: {},
                    response: {}
                });
            },
            showEdit(task) {
                that.editInfo.show = true;
                that.editInfo.addMode = false;
                that.setTaskForm({...task})
            },
            resetForm(){
                that.editInfo.task = {...that.editInfo.orgTask};
            },
            submitForm(a){
                try{
                    let task = {...that.editInfo.task};

                    task.runStatus = !!task.runStatus;
                    // 将对象的一部分数据从字符串转为对象
                    task.acquiredTime = new Date(task.acquiredTime).getTime();
                    task.finishTime = new Date(task.finishTime).getTime();
                    task.createTime = new Date(task.createTime).getTime();

                    if(task.acquiredTime == undefined) delete task.acquiredTime;
                    if(task.finishTime == undefined) delete task.finishTime;
                    if(task.createTime == undefined) delete task.createTime;

                    let temp;
                    temp = eval(`(${task.progressList})`);
                    if(temp instanceof Array) task.progressList = temp;
                    else throw new Error("progressList字段需要是一个数组");
                    
                    temp = eval(`(${task.data})`);
                    if(typeof temp == "object") task.data = temp;
                    else throw new Error("全程需要的字段需要是一个对象");

                    temp = eval(`(${task.request})`);
                    if(typeof temp == "object") task.request = temp;
                    else throw new Error("请求信息字段需要是一个对象");

                    temp = eval(`(${task.response})`);
                    if(typeof temp == "object") task.response = temp;
                    else throw new Error("响应信息字段需要是一个对象");
                    
                    if(that.editInfo.addMode) {
                        // 添加
                        that.add({
                            progressList: task.progressList,
                            data: task.data,
                            request: task.request,
                            response: task.response
                        });
                    } else {
                        // 更新
                        that.edit(task);
                    }
                }catch(e){
                    console.error("提交失败", e);
                    ElMessage.error( (e instanceof Error ? e.message : '') + '异常' + JSON.stringify(e))
                }
            },
            add(task) {
                console.log("添加任务：", task);
                warpAxios(axios.post('/api/task/add', task)
                .then(function(response) {
                    ElMessage.success('添加成功')
                    that.list();
                }))
            },
            refresh() {
                warpAxios(axios.get('/api/task/refresh')
                .then(function(response) {
                    ElMessage.success('重载成功')
                    that.list();
                }))
            },
            del(ids) {
                if(!ids) ids = that.selectIds; 
                warpAxios(axios.post('/api/task/del', {
                    ids: ids
                }).then(function(response) {
                    ElMessage.success('删除成功')
                    that.list();
                }))
            },
            edit(task) {
                console.log("更新任务：", task);
                warpAxios(axios.post('/api/task/up', task)
                .then(function(response) {
                    ElMessage.success('更新成功');
                    that.list();
                }))
            }
        }
        that = {
            ...methods,
            ...vueData
        }
        return methods;
    }
    function warpAxios(promise) {
        promise.catch(function(error) {
            console.error("请求异常", error);
            ElMessage.error('请求异常' + JSON.stringify(error))
        });
    }
</script>

<script>
    const { createApp, ref, reactive, toRefs, onMounted } = Vue;    // 动态注册 Element Plus 的图标组件
    // 动态注册 Element Plus 的图标组件
    const {ElButton, ElMessage, ElMessageBox, ElLoading, UploadProps, UploadUserFile} = ElementPlus;
    const {ElIcon} = ElementPlus;

    const vue3Composition = {
        setup() {
            const data = reactive(getData())
            const dataRef = toRefs(data);

            const methods = getMethods(data);

            onMounted(() => {
                // 加载完成
                methods.list();
            });

            return {
                ...methods,
                ...dataRef,
            }
        }
    }

    const app = createApp(vue3Composition)
        .use(ElementPlus)
        // .component('ElButton', ElButton)
        // .component('ElIcon', ElIcon)
        .mount('#app');
</script>

<style scoped>
    .el-col {
      text-align: center;
    }
    
    .countdown-footer {
      margin-top: 8px;
    }

    .margin {
        margin: 30px 0;
    }
</style>
